<?php
/*
	version 0.1 November 2011 - Florian Vacarus (florianvacarus#gmail.com)

	check for latest version on http://code.google.com/p/adodb-sqlrelay-driver/

	Released under both BSD license and Lesser GPL library license. 
	Whenever there is any discrepancy between the two licenses, 
	the BSD license will take precedence.

	set tab size to 4
	
	todo: 
		- exclude nonbindet vars from array submited
		- SelectLimit portable
*/


// security - hide paths
if (!defined('ADODB_DIR')) die();

class ADODB_sqlrelay extends ADOConnection {
	var $databaseType		= 'sqlrelay';
	var $_errorMsg			= false;
	var $_errorCode			= false;
	var $_autocommit		= true;
	var $_die_oncommit_error= false;
	var $_die_onsql_error	= false;
	var $_connectionID_db	= false;
	var $_connectionID		= false;

	function ADODB_sqlrelay() {
		return true;
	}

	function Connect($argHostname, $argUsername, $argPassword, $argDatabasename="", $mode=0) {
		$this->_errorMsg = false;
		$this->_errorCode = false;

		// $argHostname host name by host and port (0.0.0.0:9000)
		$argHostinfo=explode(":",$argHostname);
		$argHostname=$argHostinfo[0];
		$argHostport=$argHostinfo[1];

		//connect to database server in setup pooler
		$this->_connectionID_db = sqlrcon_alloc($argHostname, $argHostport , "", $argUsername, $argPassword,0,1);
		$this->_connectionID = sqlrcur_alloc($this->_connectionID_db);

		//configure sqlrelay to retrieve null as null - otherwise will return an empty string
		//the other option is $this->getNullsAsEmptyStrings();
		$this->getNullsAsNulls();

		//send a dummy sql to server because sqlrelay does not give you connection error until a sql is sent
		if (!sqlrcur_sendQuery($this->_connectionID, "select 'a' from dual")) {
			$this->_errorMsg = sqlrcur_errorMessage($this->_connectionID);
			return false;
		}

		return true;
	}

	/*
		overwrite adodb Execute subroutine because sqlrelay threat connection with a different aproach
	*/
	function Execute($sql, $inputarr=false) {
		$this->_rsParser($sql);
		if($inputarr) $this->_rsVarsBinder($sql, $inputarr);

		if(!sqlrcur_executeQuery($this->_connectionID)) {
			$this->_errorMsg = sqlrcur_errorMessage($this->_connectionID) . " :: {$sql}";
			//stop on sql error
			if($this->_die_onsql_error) die($this->_errorMsg);
			else return false;
		}
		//dump(sqlrcur_errorMessage($this->_connectionID));

		if($this->_autocommit) $this->CompleteTrans();

		$new_rs = new ADORecordset_sqlrelay($this->_connectionID);
		$new_rs->connection = $this;
		$new_rs->sql = $sql;

		return $new_rs;
	}

	function StartTrans() {
		$this->_autocommit = false;
		return true;
	}

	//wrapper for CompleteTrans
	function CommitTrans() {
		return $this->CompleteTrans();
	}

	function CompleteTrans() {
		if(!sqlrcon_commit($this->_connectionID_db)) {
			$this->_errorMsg = sqlrcur_errorMessage($this->_connectionID);
		}
		return true;
	}

	function RollbackTrans() {
		sqlrcon_rollback($this->_connectionID_db);
		return true;
	}

	function SelectLimit($sql, $nrows=-1, $offset=-1, $inputarr=false, $secs2cache=0) {
		//only for links with oracle
		//$sql="select * from (select adodb_subselect.*,rownum as ADODB_ROWNUM from ( {$sql} ) adodb_subselect ) where ADODB_ROWNUM between :adodb_offset + 1 and :adodb_offset + :adodb_nrows";
		//select * from ({$sql}) x,(select rownum nr,orig.rowid row_id from ({$sql}) orig) y where X.ROWID = Y.ROW_ID and y.nr between 5 and 10;
		$sql = "
			select * from ({$sql}) where rownum <= :adodb_offset + :adodb_nrows
			minus
			select * from ({$sql}) where rownum <= :adodb_offset
		";
		if(!$inputarr) $inputarr = array();
		$inputarr = array_merge($inputarr, array("adodb_offset" => $offset, "adodb_nrows" => $nrows));
		$new_rs = $this->Execute($sql, $inputarr);

		return $new_rs;
	} 

	//external wrapper function for _rsParser
	function PrepareSP($sql) {
		$this->_rsParser($sql);
		return true;
	}

	//stmt is set for compatibility with adodb, we use internal _connectionID
	//todo: to make a way for output binds
	function Parameter($dummy_stmt, $php_var, $db_var, $isOutput=false, $maxLen=4000, $type=false) {
		$this->_rsBindParameter($db_var, $php_var);
		return true;
	}

	private function _rsParser($sql) {
		sqlrcur_prepareQuery($this->_connectionID, $sql);
		return true;
	}

	private function _rsVarsBinder($sql, $inputarr) {
		//dump($out_sql_binds);
		//dump($inputarr);
		preg_match_all("(:\w+)", $sql, $out_sql_binds);
		foreach($inputarr as $db_var => $php_var) {
			//filter extra variables sent to sql
			if (in_array(":{$db_var}", $out_sql_binds[0]))
				$this->_rsBindParameter($db_var, $php_var);
		}
		return false;
	}

	private function _rsBindParameter($db_var, $php_var) {
		sqlrcur_inputBind($this->_connectionID, $db_var, $php_var);
		return true;
	}

	function _close() {
		sqlrcur_free($this->_connectionID);
		sqlrcon_free($this->_connectionID_db);
	}

	function getNullsAsNulls() {
		sqlrcur_getNullsAsNulls($this->_connectionID);
	}

	function getNullsAsEmptyStrings() {
		sqlrcur_getNullsAsEmptyStrings();
	}
}

class ADORecordset_sqlrelay extends ADORecordSet_array {
	var $databaseType		= 'sqlrelay';

	function ADORecordset_sqlrelay($id, $mode=false) {
		$this->_queryID = $id;
		$this->_numOfFields = sqlrcur_colCount($this->_queryID);
		$this->_numOfRows = sqlrcur_rowCount($this->_queryID);
		$this->_currentRow = 0;
		$this->_set_fields_objects();
		$this->_set_rows_in_array();
		$this->fields = $this->_array[0];
	}

	function FetchRow() {
		if (!$this->EOF) {
			$row = $this->_array[$this->_currentRow];
			if($this->_currentRow < $this->_numOfRows - 1) {
				$this->_currentRow++;
			} else {
				$this->EOF = true;
			}
		} else {
			$row = false;
		}
		return $row;
	}

	function _fetch() {
		if(!isset($this->_array[$this->_currentRow])) return false;
		else $this->fields = $this->_array[$this->_currentRow];
	}

	private function _set_fields_objects() {
		for ($i=0; $i<$this->_numOfFields; $i++) {
			
			$this->_fieldobjects[$i] = new ADOFieldObject();
			$this->_fieldobjects[$i]->name = sqlrcur_getColumnName($this->_queryID,$i);
			$this->_fieldobjects[$i]->type = sqlrcur_getColumnType($this->_queryID,$i);
			$this->_fieldobjects[$i]->max_length = sqlrcur_getColumnLength($this->_queryID,$i);
		}
	}

	private function _set_rows_in_array() {
		for($row=0; $row < $this->_numOfRows; $row++){
			for ($col=0; $col < $this->_numOfFields; $col++) {
				$this->_array[$row][$col] = sqlrcur_getField($this->_queryID, $row, $col);
				$this->_array[$row][$this->_fieldobjects[$col]->name] = sqlrcur_getField($this->_queryID, $row, $col);
			}
		}
	}
}

?>
